﻿using System;
using System.Configuration;
using System.Collections.Generic;
using Alex.Library.Log.Exceptions;
using Alex.Library.Log.Configuration;

namespace Alex.Library.Log
{
    /// <summary>
    /// 日志管理器
    /// </summary>
    public static class LoggerManager
    {
        private static IDictionary<string, ILogger> _LoggerStore;

        /// <summary>
        /// 静态构造函数
        /// </summary>
        static LoggerManager()
        {
            _LoggerStore = new Dictionary<string, ILogger>();
        }

        #region Coding

        /// <summary>
        /// 向管理器中注册日志对象
        /// </summary>
        /// <param name="name">日志唯一的名称</param>
        /// <param name="logger">日志对象</param>
        public static void RegisterLogger(string name, ILogger logger)
        {
            lock (_LoggerStore)
            {
                if (_LoggerStore.ContainsKey(name))
                {
                    throw new LoggerExistException();
                }
                _LoggerStore[name] = logger;
            }
        }

        /// <summary>
        /// 更新已注册的日志对象，新日志对象必须与旧对象类型一致
        /// </summary>
        /// <param name="name">注册名称</param>
        /// <param name="newLogger">新日志对象</param>
        /// <exception cref="UpdateLoggerException">UpdateLoggerException</exception>
        public static void UpdateLogger(string name, ILogger newLogger)
        {
            lock (_LoggerStore)
            {
                if (_LoggerStore.ContainsKey(name))
                {
                    ILogger logger = _LoggerStore[name];
                    if (logger.GetType() != newLogger.GetType())
                    {
                        throw new UpdateLoggerException("日志对象类型不匹配.");
                    }
                    logger = newLogger;
                }
            }
        }

        /// <summary>
        /// 移除日志对象
        /// </summary>
        /// <param name="name"></param>
        public static void RemoveLogger(string name)
        {
            lock (_LoggerStore)
            {
                if (_LoggerStore.ContainsKey(name))
                {
                    _LoggerStore.Remove(name);
                }
            }
        }

        /// <summary>
        /// 清除所有日志对象
        /// </summary>
        public static void Clear()
        {
            lock (_LoggerStore)
            {
                _LoggerStore.Clear();
            }
        }

        /// <summary>
        /// 获取已注册的日志个数
        /// </summary>
        /// <returns></returns>
        public static int GetLoggerCount()
        {
            lock (_LoggerStore)
            {
                return _LoggerStore.Count;
            }
        }

        /// <summary>
        /// 将日志发送到已注册的每一个日志对象，以便日志对象判断是否需要输出
        /// </summary>
        /// <param name="level">日志级别</param>
        /// <param name="message">日志内容</param>
        public static void WriteLog(LogLevel level, string message)
        {
            lock (_LoggerStore)
            {
                foreach (ILogger logger in _LoggerStore.Values)
                {
                    logger.Flush(level, message);
                }
            }
        }

        #endregion

        #region Configuration

        /// <summary>
        /// 加载配置
        /// </summary>
        public static void LoadConfiguration()
        {
            string sectionName = "nlogger";
            NLoggerConfigurationSection section = 
                (NLoggerConfigurationSection)ConfigurationManager.GetSection(sectionName);
            lock (_LoggerStore)
            {
                AddLoggersToStore(section.FileLoggers);
                AddLoggerToStore(section.ConsoleLogger);
                AddLoggerToStore(section.TraceLogger);
                AddLoggersToStore(section.XmlLoggers);
                AddLoggersToStore(section.MailLoggers);
                AddLoggersToStore(section.CustomLoggers);
            }
        }

        /// <summary>
        /// 将配置信息转换为日志对象并添加到缓存中
        /// </summary>
        /// <param name="loggerElement">日志节点</param>
        private static void AddLoggerToStore(LoggerElement loggerElement)
        {
            if (String.IsNullOrEmpty(loggerElement.Name))
            {
                return;
            }
            if (_LoggerStore.ContainsKey(loggerElement.Name))
            {
                throw new LoggerExistException();
            }
            ILogger logger = loggerElement.GetLogger();
            _LoggerStore[loggerElement.Name] = logger;
        }

        /// <summary>
        /// 将配置信息转换为日志对象并添加到缓存中
        /// </summary>
        /// <typeparam name="T">日志类型</typeparam>
        /// <param name="loggerElementCollection">配置节点集合</param>
        private static void AddLoggersToStore<T>(LoggerElementCollection<T> loggerElementCollection)
            where T : ILogger
        {
            foreach (LoggerElement element in loggerElementCollection)
            {
                if (_LoggerStore.ContainsKey(element.Name))
                {
                    throw new LoggerExistException();
                }
                ILogger logger = element.GetLogger();
                _LoggerStore[element.Name] = logger;
            }
        }

        #endregion
    }
}
